package com.wei.czz.framework.common.manager;

import com.alibaba.fastjson2.JSON;
import com.wei.czz.common.constant.Constant;
import com.wei.czz.common.constant.EntityConstant;
import com.wei.czz.common.constant.RedisConstant;
import com.wei.czz.common.dto.common.KeyValue;
import com.wei.czz.common.dto.common.NameValue;
import com.wei.czz.common.dto.common.sms.*;
import com.wei.czz.common.dto.echarts.Line;
import com.wei.czz.common.dto.echarts.Pie;
import com.wei.czz.common.dto.echarts.Scatter;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.ResultEnum;
import com.wei.czz.common.enums.common.sms.SmsChannelEnum;
import com.wei.czz.common.enums.common.sms.SmsTypeEnum;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.common.po.UserPo;
import com.wei.czz.common.tool.PageDto;
import com.wei.czz.common.utils.CacheKeyUtils;
import com.wei.czz.common.utils.CopyUtils;
import com.wei.czz.common.utils.SecurityUtils;
import com.wei.czz.common.utils.TimeUtils;
import com.wei.czz.common.vo.common.UpdateStatusVo;
import com.wei.czz.common.vo.common.sms.SmsTemplateFormVo;
import com.wei.czz.common.vo.common.sms.SmsTemplateStatVo;
import com.wei.czz.common.vo.common.sms.SmsTemplateVo;
import com.wei.czz.framework.common.entity.SmsLogEntity;
import com.wei.czz.framework.common.entity.SmsTemplateEntity;
import com.wei.czz.framework.common.entity.SmsTemplateFlowEntity;
import com.wei.czz.framework.common.helper.CacheHelper;
import com.wei.czz.framework.common.helper.SmsSendHelper;
import com.wei.czz.framework.common.handler.redis.RedisHashHandler;
import com.wei.czz.framework.common.service.*;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2024-06-18 11:24:54
 * className: SmsTemplateManager
 * version: 1.0
 * description:
 */
@Component
@AllArgsConstructor
public class SmsTemplateManager {

    private static final Logger log = LoggerFactory.getLogger(SmsTemplateManager.class);

    private final SmsTemplateService smsTemplateService;

    private final SmsTemplateFlowService smsTemplateFlowService;

    private final SmsLogService smsLogService;

    private final SmsSendHelper smsSendHelper;

    private final RedisHashHandler redisHashHandler;

    private final CacheHelper cacheHelper;

    private final RedissonClient redissonClient;

    private final AsyncService asyncService;

    public void saveSmsTemplate(SmsTemplateVo smsTemplateVo) {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        String hashKey = CacheKeyUtils.getRedisHashKey(EntityConstant.SMS_TEMPLATE);
        String cacheKey = smsTemplateVo.getType().toString();
        /*
            判断短信模板是否存在
         */
        SmsTemplateEntity smsTemplate = redisHashHandler.get(hashKey, cacheKey);
        if (Objects.nonNull(smsTemplate)) {
            log.info("短信模板已存在");
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "短信模板已存在，请确认");
        }

        String lockKey = RedisConstant.LOCK + hashKey + Constant.SPLIT + cacheKey;
        RLock lock = redissonClient.getLock(lockKey);
        boolean bool = lock.tryLock();
        log.info("保存短信模板，尝试加锁完成。lockKey={} bool={}", lock, bool);
        if (!bool) {
            throw new CzzException(ResultEnum.TRY_LOCK_FAIL.getCode(), "该短信模板正在操作中，请确认后重试");
        }

        try {

            /*
                判断短信模板是否存在
             */
            smsTemplate = smsTemplateService.find(smsTemplateVo.getType());
            if (Objects.nonNull(smsTemplate)) {
                throw new CzzException(ResultEnum.DATA_DUPLICATION.getCode(), "短信模板已存在，请确认后重试");
            }

            /*
                获取短信渠道服务类
             */
            SmsService smsService = smsSendHelper.getSmsService(smsTemplateVo.getChannel());

            /*
                校验短信模板是否正确
             */
            bool = smsService.validTemplateParams(smsTemplateVo.getContent(), new HashSet<>(smsTemplateVo.getParamSet()));
            log.info("短信模板校验完成。bool={}", bool);
            if (!bool) {
                String message = "短信模板不满足保存条件，请检查短信模板和模板参数后重新提交";
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), message);
            }
            // 短信渠道参数
            String channelParam = JSON.toJSONString(smsTemplateVo.getChannelParamMap());
            // 模板预设字段
            String params = StringUtils.join(smsTemplateVo.getParamSet(), ',');

            /*
                保存短信模板
             */
            SmsTemplateEntity saveSmsTemplate = new SmsTemplateEntity();
            saveSmsTemplate.setType(smsTemplateVo.getType())
                    .setCode(smsTemplateVo.getCode())
                    .setChannel(smsTemplateVo.getChannel())
                    .setChannelParam(channelParam)
                    .setContent(smsTemplateVo.getContent())
                    .setParams(params)
                    .setVersion(CommonEnum.ONE.getValue())
                    .setStatus(CommonEnum.ZERO.getValue())
                    .setDeleteStatus(CommonEnum.ZERO.getValue())
                    .setUpdateTime(date)
                    .setUpdateUser(StringUtils.EMPTY)
                    .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                    .setCreateTime(date)
                    .setCreateUser(userPo.getUsername())
                    .setCreateUserId(userPo.getUserId());
            smsTemplateService.saveOrEdit(saveSmsTemplate);

            /*
                缓存短信模板
             */
            redisHashHandler.put(hashKey, cacheKey, saveSmsTemplate);

            asyncService.execute(() -> {
                /*
                    保存短信模板流水
                 */
                SmsTemplateFlowEntity smsTemplateFlow = CopyUtils.map(saveSmsTemplate, SmsTemplateFlowEntity.class);
                smsTemplateFlow.setId(null)
                                .setMasterId(saveSmsTemplate.getId());
                smsTemplateFlowService.saveOrEdit(smsTemplateFlow);
            });

        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    public PageDto<SmsTemplateDto> getSmsTemplatePageList(SmsTemplateFormVo smsTemplateFormVo) {

        /*
            缓存请求参数
         */
        String cacheKey = CacheKeyUtils.getParamCacheKey(EntityConstant.SMS_TEMPLATE);
        cacheHelper.cache(cacheKey, smsTemplateFormVo);

        /*
            分页获取短信模板
         */
        PageDto<SmsTemplateEntity> pageDto = smsTemplateService.getPageList(smsTemplateFormVo);
        if (pageDto.isEmpty()) {
            return pageDto.rebuild();
        }

        List<SmsTemplateEntity> smsTemplateList = pageDto.getList();

        List<SmsTemplateDto> smsTemplateDtoList = CopyUtils.mapList(smsTemplateList, smsTemplate -> {
            SmsTemplateDto smsTemplateDto = CopyUtils.map(smsTemplate, SmsTemplateDto.class);
            smsTemplateDto.setTypeName(SmsTypeEnum.getName(smsTemplate.getType()))
                    .setChannelName(SmsChannelEnum.getName(smsTemplate.getChannel()))
                    .setStatusName(CommonEnum.getStatusName(smsTemplate.getStatus()));
            return smsTemplateDto;
        });

        // 封装返回
        return pageDto.rebuild(smsTemplateDtoList);
    }

    public SmsTemplatePageEnumDto getSmsTemplatePageEnum() {
        /*
            获取请求参数
         */
        String cacheKey = CacheKeyUtils.getParamCacheKey(EntityConstant.SMS_TEMPLATE);
        SmsTemplateFormVo smsTemplateFormVo = cacheHelper.get(cacheKey, SmsTemplateFormVo.class);

        List<NameValue<Integer>> statusList = CommonEnum.getStatusList();

        SmsTemplatePageEnumDto smsTemplatePageEnumDto = new SmsTemplatePageEnumDto();
        smsTemplatePageEnumDto.setTypeList(SmsTypeEnum.getList())
                .setChannelList(SmsChannelEnum.getList())
                .setStatusList(statusList)
                .setSmsTemplateFormVo(smsTemplateFormVo);
        return smsTemplatePageEnumDto;
    }

    public SmsTemplateDetailDto getSmsTemplateDetail(Long id) {

        /*
            获取短信模板
         */
        SmsTemplateEntity smsTemplate = smsTemplateService.get(id);

        /*
            获取短信渠道参数映射
         */
        Map<String, NameValue<String>> channelParamMap = smsSendHelper.getChannelParam(smsTemplate.getChannel(),
                smsTemplate.getChannelParam());

        SmsTemplateDetailDto smsTemplateDetailDto = CopyUtils.map(smsTemplate, SmsTemplateDetailDto.class);
        smsTemplateDetailDto.setTypeName(SmsTypeEnum.getName(smsTemplate.getType()))
                .setChannelName(SmsChannelEnum.getName(smsTemplate.getChannel()))
                .setStatusName(CommonEnum.getStatusName(smsTemplate.getStatus()))
                .setParamList(Arrays.asList(smsTemplate.getParams().split(",")))
                .setChannelParamMap(channelParamMap);
        return smsTemplateDetailDto;
    }

    public Map<String, NameValue<String>> getChannelParam(Long id, Integer channel) {

        /*
            获取短信渠道参数
         */
        String channelParam = Optional.ofNullable(id)
                .map(smsTemplateService::get)
                .filter(smsTemplate -> smsTemplate.getChannel().equals(channel))
                .map(SmsTemplateEntity::getChannelParam)
                .orElse(null);

        /*
            获取短信渠道参数映射
         */
        return smsSendHelper.getChannelParam(channel, channelParam);
    }

    public SmsTemplateStatDto getSmsTemplateStat(SmsTemplateStatVo smsTemplateStatVo) {

        //
        smsTemplateStatVo.setEndDate(TimeUtils.getEndDate(smsTemplateStatVo.getEndDate()));

        /*
            获取短信发送记录
         */
        List<SmsLogEntity> smsLogList = smsLogService.findList(null, null, smsTemplateStatVo.getType(),
                smsTemplateStatVo.getVersion(), smsTemplateStatVo.getStartDate(), smsTemplateStatVo.getEndDate());

        /*
            数据计算
         */
        DateFormat hourFormat = new SimpleDateFormat("yyyy-MM-dd HH");
        DateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd");
        DateFormat monthFormat = new SimpleDateFormat("yyyy-MM");

        Map<String, List<SmsLogEntity>> smsLogMap = new HashMap<>();
        Map<Integer, Integer> smsChannelMap = new HashMap<>();

        for (SmsLogEntity smsLog : smsLogList) {

            String key = hourFormat.format(smsLog.getCreateTime());
            List<SmsLogEntity> list = smsLogMap.computeIfAbsent(key, k -> new ArrayList<>());
            list.add(smsLog);

            key = dayFormat.format(smsLog.getCreateTime());
            list = smsLogMap.computeIfAbsent(key, k -> new ArrayList<>());
            list.add(smsLog);

            key = monthFormat.format(smsLog.getCreateTime());
            list = smsLogMap.computeIfAbsent(key, k -> new ArrayList<>());
            list.add(smsLog);

            Integer count = smsChannelMap.getOrDefault(smsLog.getChannel(), 0);
            smsChannelMap.put(smsLog.getChannel(), count + 1);
        }

        SmsTemplateStatDto smsTemplateStatDto = new SmsTemplateStatDto();
        if (smsTemplateStatVo.getDateType().equals(0)) {
            smsTemplateStatDto.setOneDayScatter(this.buildOneDayScatter(smsLogMap));
        }
        smsTemplateStatDto.setSendLine(this.buildSendLine(smsTemplateStatVo, smsLogMap));
        smsTemplateStatDto.setChannelPie(this.buildChannelPie(smsChannelMap));
        smsTemplateStatDto.setFlowList(this.buildFlowList(smsTemplateStatVo));

        return smsTemplateStatDto;
    }

    public SmsTemplateFlowDto getSmsTemplateFlowDetail(Long masterId, Integer version) {

        /*
            获取短信模板流水
         */
        SmsTemplateFlowEntity smsTemplateFlow = smsTemplateFlowService.find(masterId, version);

        SmsTemplateFlowDto smsTemplateFlowDto = CopyUtils.map(smsTemplateFlow, SmsTemplateFlowDto.class);
        smsTemplateFlowDto.setTypeName(SmsTypeEnum.getName(smsTemplateFlow.getType()))
                .setChannelName(SmsChannelEnum.getName(smsTemplateFlow.getChannel()));
        return smsTemplateFlowDto;
    }

    public void updateSmsTemplate(SmsTemplateVo smsTemplateVo) {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        String cacheKey = smsTemplateVo.getType().toString();

        /*
            获取短信模板
         */
        SmsTemplateEntity smsTemplate = smsTemplateService.get(smsTemplateVo.getId());
        if (!Objects.equals(smsTemplate.getVersion(), smsTemplateVo.getVersion())) {
            throw new CzzException(ResultEnum.DATA_DUPLICATION.getCode(), "短信模板已变更，请确认后重试");
        }

        /*
            获取短信渠道服务类
         */
        SmsService smsService = smsSendHelper.getSmsService(smsTemplateVo.getChannel());

        /*
            校验短信模板是否正确
         */
        boolean bool = smsService.validTemplateParams(smsTemplateVo.getContent(), new HashSet<>(smsTemplateVo.getParamSet()));
        if (!bool) {
            String message = "短信模板不满足修改条件，请检查短信模板和模板参数后重新提交";
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), message);
        }
        // 短信渠道参数
        String channelParam = JSON.toJSONString(smsTemplateVo.getChannelParamMap());
        // 模板预设字段
        String params = StringUtils.join(smsTemplateVo.getParamSet(), ',');

        /*
            乐观锁更新短信模板
         */
        SmsTemplateEntity updateSmsTemplate = new SmsTemplateEntity();
        updateSmsTemplate.setId(smsTemplateVo.getId())
                .setType(smsTemplateVo.getType())
                .setCode(smsTemplateVo.getCode())
                .setChannel(smsTemplateVo.getChannel())
                .setChannelParam(channelParam)
                .setContent(smsTemplateVo.getContent())
                .setParams(params)
                .setVersion(smsTemplateVo.getVersion() + 1)
                .setUpdateTime(date)
                .setUpdateUser(userPo.getUsername())
                .setUpdateUserId(userPo.getUserId());
        int count = smsTemplateService.optimisticUpdate(updateSmsTemplate);
        if (count == 0) {
            throw new CzzException(ResultEnum.REFRESH.getCode(), "短信模板已变更，请确认后重新操作");
        }

        /*
            缓存短信模板
         */
        redisHashHandler.put(CacheKeyUtils.getRedisHashKey(EntityConstant.SMS_TEMPLATE), cacheKey, updateSmsTemplate);

        asyncService.execute(() -> {
            /*
                保存短信模板流水
             */
            SmsTemplateFlowEntity smsTemplateFlow = CopyUtils.map(updateSmsTemplate, SmsTemplateFlowEntity.class);
            smsTemplateFlow.setId(null)
                    .setMasterId(updateSmsTemplate.getId())
                    .setDeleteStatus(CommonEnum.ZERO.getValue())
                    .setUpdateTime(date)
                    .setUpdateUser(StringUtils.EMPTY)
                    .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                    .setCreateTime(date)
                    .setCreateUser(userPo.getUsername())
                    .setCreateUserId(userPo.getUserId());
            smsTemplateFlowService.saveOrEdit(smsTemplateFlow);
        });
    }

    public void updateSmsTemplateStatus(UpdateStatusVo updateStatusVo) {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        List<Long> idList = updateStatusVo.getIdList();
        Integer status = updateStatusVo.getStatus();

        /*
            获取短信模板
         */
        List<SmsTemplateEntity> smsTemplateList = smsTemplateService.getList(idList);
        if (smsTemplateList.isEmpty()) {
            throw new CzzException(ResultEnum.ILLEGAL_FAIL);
        }

        /*
            修改短信模板状态
         */
        List<SmsTemplateEntity> updateSmsTemplateList = CopyUtils.mapList(idList, id -> {
            SmsTemplateEntity updateSmsTemplate = new SmsTemplateEntity();
            updateSmsTemplate.setId(id)
                    .setStatus(status)
                    .setUpdateTime(date)
                    .setUpdateUser(userPo.getUsername())
                    .setUpdateUserId(userPo.getUserId());
            return updateSmsTemplate;
        });
        smsTemplateService.batchUpdate(updateSmsTemplateList);

        /*
            删除短信模板缓存
         */
        // 收集短信类型
        List<String> typeList = CopyUtils.mapList(smsTemplateList, smsTemplate -> smsTemplate.getType().toString());
        // 删除缓存
        redisHashHandler.delete(CacheKeyUtils.getRedisHashKey(EntityConstant.SMS_TEMPLATE), typeList);
    }

    public void deleteSmsTemplate(List<Long> idList) {

        /*
            获取短信模板
         */
        List<SmsTemplateEntity> smsTemplateList = smsTemplateService.getList(idList);

        /*
            删除短信模板
         */
        smsTemplateService.delete(idList);

        /*
            删除短信模板缓存
         */
        // 收集短信类型
        List<String> typeList = CopyUtils.mapList(smsTemplateList, smsTemplate -> smsTemplate.getType().toString());
        // 删除缓存
        redisHashHandler.delete(CacheKeyUtils.getRedisHashKey(EntityConstant.SMS_TEMPLATE), typeList);
    }

    /**
     * 构造今日数据生成的散点图
     * 每分钟短信发送总数散点图
     * @param smsLogMap 短信发送记录映射
     * @return 散点图对象
     */
    private Scatter<Long, Long, Integer> buildOneDayScatter(Map<String, List<SmsLogEntity>> smsLogMap) {
        log.info("开始构造今日数据生成的散点图");

        Calendar calendar = Calendar.getInstance();
        int hour = calendar.get(Calendar.HOUR_OF_DAY);

        // 设置小时数值
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        // 设置分钟数值
        calendar.set(Calendar.MINUTE, 0);
        // 设置秒数数值
        calendar.set(Calendar.SECOND, 0);
        // 设置毫秒数值
        calendar.set(Calendar.MILLISECOND, 0);

        Date date = calendar.getTime();
        DateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd");
        DateFormat minuteFormat = new SimpleDateFormat("HH:mm");

        /*
            获取今日短信发送记录列表
         */
        List<SmsLogEntity> smsLogList = smsLogMap.getOrDefault(dayFormat.format(date), Collections.emptyList());

        Map<String, Integer> smsLogCountMap = new HashMap<>();
        for (SmsLogEntity smsLog : smsLogList) {
            String key = minuteFormat.format(smsLog.getCreateTime());

            Integer count = smsLogCountMap.getOrDefault(key, 0);
            smsLogCountMap.put(key, count + 1);
        }

        /*
            生成x轴列表
         */
        // 多一个小时
        hour += 1;

        long startMillis = calendar.getTimeInMillis();
        long endMillis = startMillis + (long) hour * 60 * Constant.MINUTE_NUM;
//        log.info("startMillis={}", TimeUtils.format(new Date(startMillis)));
//        log.info("endMillis={}", TimeUtils.format(new Date(endMillis)));

        List<Long> xAxisList = new ArrayList<>();
        List<KeyValue<Long, Integer>> dataList = new ArrayList<>();

        for (long millis = startMillis; millis <= endMillis; millis += Constant.MINUTE_NUM) {
            date = new Date(millis);

            String key = minuteFormat.format(date);
            Integer count = smsLogCountMap.getOrDefault(key, 0);

            if (count == 0) {
                // todo mock数据
                count = new Random().nextInt(100);
            }

            if (count > 0) {
                dataList.add(new KeyValue<>(millis, count));
                xAxisList.add(millis);
            }
        }

        log.info("构造今日数据生成的散点图结束");

        Scatter<Long, Long, Integer> scatter = new Scatter<>();
        scatter.setXAxisList(xAxisList)
                .setDataList(dataList);
        return scatter;
    }

    /**
     * 构造时间范围内发送记录折线图
     * 发送成功数、发送失败数折线图
     * @param smsTemplateStatVo 参数对象
     * @param smsLogMap         短信发送记录映射
     * @return 折线图对象
     */
    private Line<String, Integer> buildSendLine(SmsTemplateStatVo smsTemplateStatVo,
                                              Map<String, List<SmsLogEntity>> smsLogMap) {
        log.info("开始构造时间范围内发送记录折线图");

        DateFormat hourFormat = new SimpleDateFormat("yyyy-MM-dd HH");
        DateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd");
        long oneHour = 60L * Constant.MINUTE_NUM;

        List<String> xAxisList = new ArrayList<>();
        List<Integer> totalList = new ArrayList<>();
        List<Integer> successList = new ArrayList<>();
        List<Integer> failList = new ArrayList<>();

        long span = smsTemplateStatVo.getEndDate().getTime() - smsTemplateStatVo.getStartDate().getTime();
        if (span / oneHour > 24) {
            // 按日计算
            for (long i = smsTemplateStatVo.getStartDate().getTime();
                 i < smsTemplateStatVo.getEndDate().getTime(); i += Constant.ONE_DAY_NUM) {
                String key = dayFormat.format(new Date(i));

                List<SmsLogEntity> list = smsLogMap.getOrDefault(key, Collections.emptyList());
                int successCount = 0;
                int failCount = 0;
                for (SmsLogEntity smsLog : list) {
                    if (CommonEnum.ZERO.getValue().equals(smsLog.getStatus())) {
                        successCount += 1;
                    } else {
                        failCount += 1;
                    }
                }

                if (true) {
                    // TODO mock数据
                    if (successCount == 0) {
                        successCount = new Random().nextInt(100);
                    }
                    if (failCount == 0) {
                        failCount = new Random().nextInt(20);
                    }
                }

                xAxisList.add(key);
                totalList.add(successCount + failCount);
                successList.add(successCount);
                failList.add(failCount);
            }

        } else {
            // 按时计算
            for (long i = smsTemplateStatVo.getStartDate().getTime();
                 i < smsTemplateStatVo.getEndDate().getTime(); i += Constant.MINUTE_NUM * 60) {
                String key = hourFormat.format(new Date(i));

                List<SmsLogEntity> list = smsLogMap.getOrDefault(key, Collections.emptyList());
                int successCount = 0;
                int failCount = 0;
                for (SmsLogEntity smsLog : list) {
                    if (CommonEnum.ZERO.getValue().equals(smsLog.getStatus())) {
                        successCount += 1;
                    } else {
                        failCount += 1;
                    }
                }

                if (true) {
                    // TODO mock数据
                    if (successCount == 0) {
                        successCount = new Random().nextInt(200);
                    }
                    if (failCount == 0) {
                        failCount = new Random().nextInt(50);
                    }
                }

                xAxisList.add(key);
                totalList.add(successCount + failCount);
                successList.add(successCount);
                failList.add(failCount);
            }
        }

        log.info("构造时间范围内发送记录折线图结束");

        Line<String, Integer> line = new Line<>();
        line.setXAxisList(xAxisList)
                .setDataList(Arrays.asList(totalList, successList, failList));
        return line;
    }

    /**
     * 构造当前版本使用哥短信渠道占比饼图
     * @param smsChannelMap 短信渠道使用数量映射
     * @return 饼图对象
     */
    private Pie<Integer> buildChannelPie(Map<Integer, Integer> smsChannelMap) {

        if (true) {
            // todo mock数据
            smsChannelMap.put(SmsChannelEnum.ALI.getValue(), 6);
            smsChannelMap.put(SmsChannelEnum.HW.getValue(), 3);
            smsChannelMap.put(SmsChannelEnum.TX.getValue(), 1);
        }

        List<NameValue<Integer>> dataList = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : smsChannelMap.entrySet()) {
            Integer channel = entry.getKey();
            Integer count = entry.getValue();

            dataList.add(new NameValue<>(SmsChannelEnum.getName(channel), count));
        }
        dataList.sort((nv1, nv2) -> nv2.getValue().compareTo(nv1.getValue()));

        List<String> legendList = CopyUtils.mapList(dataList, NameValue::getName);

        Pie<Integer> pie = new Pie<>();
        pie.setLegendList(legendList)
                .setDataList(Collections.singletonList(dataList));
        return pie;
    }

    /**
     * 构造短信模板流水统计列表
     * @param smsTemplateStatVo 参数对象
     * @return 短信模板流水统计列表
     */
    private List<SmsTemplateFlowStatDto> buildFlowList(SmsTemplateStatVo smsTemplateStatVo) {

        /*
            获取短信模板流水
         */
        List<SmsTemplateFlowEntity> smsTemplateFlowList = smsTemplateFlowService.findList(null,
                smsTemplateStatVo.getType(), null);
        Map<Integer, SmsTemplateFlowEntity> smsTemplateFlowMap = CopyUtils.listToMap(
                smsTemplateFlowList,
                SmsTemplateFlowEntity::getVersion, Function.identity(),
                (o1, o2) -> o1
        );

        /*
            获取短信模板流水统计
         */
        List<SmsTemplateFlowStatDto> smsTemplateFlowDtoList = smsLogService.findStatList(smsTemplateStatVo.getType(),
                null);

        smsTemplateFlowDtoList = smsTemplateFlowDtoList.stream()
                .peek(smsTemplateFlowStatDto -> {
                    SmsTemplateFlowEntity smsTemplateFlow = smsTemplateFlowMap.get(smsTemplateFlowStatDto.getVersion());
                    if (Objects.isNull(smsTemplateFlow)) {
                        log.info("找不到对应版本的短信模板流水。type={} version={}", smsTemplateStatVo.getType(),
                                smsTemplateFlowStatDto.getVersion());
                        return;
                    }
                    // 获取下一个短信模板对象
                    SmsTemplateFlowEntity nextSmsTemplateFlow = smsTemplateFlowMap.get(smsTemplateFlowStatDto.getVersion() + 1);

                    smsTemplateFlowStatDto.setId(smsTemplateFlow.getId().toString())
                            .setStartTime(smsTemplateFlow.getCreateTime())
                            .setEndTime(
                                    Optional.ofNullable(nextSmsTemplateFlow).map(SmsTemplateFlowEntity::getCreateTime)
                                            .orElse(null)
                            );
                })
                .sorted(Comparator.comparing(SmsTemplateFlowStatDto::getVersion).reversed())
                .collect(Collectors.toList());

        return smsTemplateFlowDtoList;
    }
}
